001    /*
002     *  Copyright 2001-2006 Stephen Colebourne
003     *
004     *  Licensed under the Apache License, Version 2.0 (the "License");
005     *  you may not use this file except in compliance with the License.
006     *  You may obtain a copy of the License at
007     *
008     *      http://www.apache.org/licenses/LICENSE-2.0
009     *
010     *  Unless required by applicable law or agreed to in writing, software
011     *  distributed under the License is distributed on an "AS IS" BASIS,
012     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     *  See the License for the specific language governing permissions and
014     *  limitations under the License.
015     */
016    package org.joda.time;
017    
018    import java.io.Serializable;
019    import java.util.Calendar;
020    import java.util.Date;
021    import java.util.Locale;
022    
023    import org.joda.time.base.BasePartial;
024    import org.joda.time.chrono.ISOChronology;
025    import org.joda.time.field.AbstractPartialFieldProperty;
026    import org.joda.time.field.FieldUtils;
027    import org.joda.time.format.ISODateTimeFormat;
028    
029    /**
030     * YearMonthDay is an immutable partial supporting the year, monthOfYear
031     * and dayOfMonth fields.
032     * <p>
033     * NOTE: This class only supports the three fields listed above. Thus, you
034     * cannot query the dayOfWeek or centuryOfEra fields for example.
035     * The new <code>LocalDate</code> class removes this restriction.
036     * <p>
037     * Calculations on YearMonthDay are performed using a {@link Chronology}.
038     * This chronology is set to be in the UTC time zone for all calculations.
039     * <p>
040     * Each individual field can be queried in two ways:
041     * <ul>
042     * <li><code>getMonthOfYear()</code>
043     * <li><code>monthOfYear().get()</code>
044     * </ul>
045     * The second technique also provides access to other useful methods on the
046     * field:
047     * <ul>
048     * <li>numeric value - <code>monthOfYear().get()</code>
049     * <li>text value - <code>monthOfYear().getAsText()</code>
050     * <li>short text value - <code>monthOfYear().getAsShortText()</code>
051     * <li>maximum/minimum values - <code>monthOfYear().getMaximumValue()</code>
052     * <li>add/subtract - <code>monthOfYear().addToCopy()</code>
053     * <li>set - <code>monthOfYear().setCopy()</code>
054     * </ul>
055     * <p>
056     * YearMonthDay is thread-safe and immutable, provided that the Chronology is as well.
057     * All standard Chronology classes supplied are thread-safe and immutable.
058     *
059     * @author Stephen Colebourne
060     * @since 1.0
061     * @deprecated Use LocalDate which has a much better internal implementation and
062     *  has been available since 1.3
063     */
064    public final class YearMonthDay
065            extends BasePartial
066            implements ReadablePartial, Serializable {
067    
068        /** Serialization version */
069        private static final long serialVersionUID = 797544782896179L;
070        /** The singleton set of field types */
071        private static final DateTimeFieldType[] FIELD_TYPES = new DateTimeFieldType[] {
072            DateTimeFieldType.year(),
073            DateTimeFieldType.monthOfYear(),
074            DateTimeFieldType.dayOfMonth(),
075        };
076    
077        /** The index of the year field in the field array */
078        public static final int YEAR = 0;
079        /** The index of the monthOfYear field in the field array */
080        public static final int MONTH_OF_YEAR = 1;
081        /** The index of the dayOfMonth field in the field array */
082        public static final int DAY_OF_MONTH = 2;
083    
084        //-----------------------------------------------------------------------
085        /**
086         * Constructs a YearMonthDay from a <code>java.util.Calendar</code>
087         * using exactly the same field values avoiding any time zone effects.
088         * <p>
089         * Each field is queried from the Calendar and assigned to the YearMonthDay.
090         * This is useful if you have been using the Calendar as a local date,
091         * ignoing the zone.
092         * <p>
093         * This factory method ignores the type of the calendar and always
094         * creates a YearMonthDay with ISO chronology. It is expected that you
095         * will only pass in instances of <code>GregorianCalendar</code> however
096         * this is not validated.
097         *
098         * @param calendar  the Calendar to extract fields from
099         * @return the created YearMonthDay
100         * @throws IllegalArgumentException if the calendar is null
101         * @throws IllegalArgumentException if the date is invalid for the ISO chronology
102         * @since 1.2
103         */
104        public static YearMonthDay fromCalendarFields(Calendar calendar) {
105            if (calendar == null) {
106                throw new IllegalArgumentException("The calendar must not be null");
107            }
108            return new YearMonthDay(
109                calendar.get(Calendar.YEAR),
110                calendar.get(Calendar.MONTH) + 1,
111                calendar.get(Calendar.DAY_OF_MONTH)
112            );
113        }
114    
115        /**
116         * Constructs a YearMonthDay from a <code>java.util.Date</code>
117         * using exactly the same field values avoiding any time zone effects.
118         * <p>
119         * Each field is queried from the Date and assigned to the YearMonthDay.
120         * This is useful if you have been using the Date as a local date,
121         * ignoing the zone.
122         * <p>
123         * This factory method always creates a YearMonthDay with ISO chronology.
124         *
125         * @param date  the Date to extract fields from
126         * @return the created YearMonthDay
127         * @throws IllegalArgumentException if the calendar is null
128         * @throws IllegalArgumentException if the date is invalid for the ISO chronology
129         * @since 1.2
130         */
131        public static YearMonthDay fromDateFields(Date date) {
132            if (date == null) {
133                throw new IllegalArgumentException("The date must not be null");
134            }
135            return new YearMonthDay(
136                date.getYear() + 1900,
137                date.getMonth() + 1,
138                date.getDate()
139            );
140        }
141    
142        //-----------------------------------------------------------------------
143        /**
144         * Constructs a YearMonthDay with the current date, using ISOChronology in
145         * the default zone to extract the fields.
146         * <p>
147         * The constructor uses the default time zone, resulting in the local time
148         * being initialised. Once the constructor is complete, all further calculations
149         * are performed without reference to a timezone (by switching to UTC).
150         */
151        public YearMonthDay() {
152            super();
153        }
154    
155        /**
156         * Constructs a YearMonthDay with the current date, using ISOChronology in
157         * the specified zone to extract the fields.
158         * <p>
159         * The constructor uses the specified time zone to obtain the current date.
160         * Once the constructor is complete, all further calculations
161         * are performed without reference to a timezone (by switching to UTC).
162         * 
163         * @param zone  the zone to use, null means default zone
164         * @since 1.1
165         */
166        public YearMonthDay(DateTimeZone zone) {
167            super(ISOChronology.getInstance(zone));
168        }
169    
170        /**
171         * Constructs a YearMonthDay with the current date, using the specified chronology
172         * and zone to extract the fields.
173         * <p>
174         * The constructor uses the time zone of the chronology specified.
175         * Once the constructor is complete, all further calculations are performed
176         * without reference to a timezone (by switching to UTC).
177         *
178         * @param chronology  the chronology, null means ISOChronology in the default zone
179         */
180        public YearMonthDay(Chronology chronology) {
181            super(chronology);
182        }
183    
184        /**
185         * Constructs a YearMonthDay extracting the partial fields from the specified
186         * milliseconds using the ISOChronology in the default zone.
187         * <p>
188         * The constructor uses the default time zone, resulting in the local time
189         * being initialised. Once the constructor is complete, all further calculations
190         * are performed without reference to a timezone (by switching to UTC).
191         *
192         * @param instant  the milliseconds from 1970-01-01T00:00:00Z
193         */
194        public YearMonthDay(long instant) {
195            super(instant);
196        }
197    
198        /**
199         * Constructs a YearMonthDay extracting the partial fields from the specified
200         * milliseconds using the chronology provided.
201         * <p>
202         * The constructor uses the time zone of the chronology specified.
203         * Once the constructor is complete, all further calculations are performed
204         * without reference to a timezone (by switching to UTC).
205         *
206         * @param instant  the milliseconds from 1970-01-01T00:00:00Z
207         * @param chronology  the chronology, null means ISOChronology in the default zone
208         */
209        public YearMonthDay(long instant, Chronology chronology) {
210            super(instant, chronology);
211        }
212    
213        /**
214         * Constructs a YearMonthDay from an Object that represents a time.
215         * <p>
216         * The recognised object types are defined in
217         * {@link org.joda.time.convert.ConverterManager ConverterManager} and
218         * include ReadableInstant, String, Calendar and Date.
219         * The String formats are described by {@link ISODateTimeFormat#dateOptionalTimeParser()}.
220         * <p>
221         * The chronology used will be derived from the object, defaulting to ISO.
222         * <p>
223         * NOTE: Prior to v1.3 the string format was described by
224         * {@link ISODateTimeFormat#dateTimeParser()}. Time ony strings are now rejected.
225         *
226         * @param instant  the datetime object, null means now
227         * @throws IllegalArgumentException if the instant is invalid
228         */
229        public YearMonthDay(Object instant) {
230            super(instant, null, ISODateTimeFormat.dateOptionalTimeParser());
231        }
232    
233        /**
234         * Constructs a YearMonthDay from an Object that represents a time, using the
235         * specified chronology.
236         * <p>
237         * The recognised object types are defined in
238         * {@link org.joda.time.convert.ConverterManager ConverterManager} and
239         * include ReadableInstant, String, Calendar and Date.
240         * The String formats are described by {@link ISODateTimeFormat#dateOptionalTimeParser()}.
241         * <p>
242         * The constructor uses the time zone of the chronology specified.
243         * Once the constructor is complete, all further calculations are performed
244         * without reference to a timezone (by switching to UTC).
245         * The specified chronology overrides that of the object.
246         * <p>
247         * NOTE: Prior to v1.3 the string format was described by
248         * {@link ISODateTimeFormat#dateTimeParser()}. Time only strings are now rejected.
249         *
250         * @param instant  the datetime object, null means now
251         * @param chronology  the chronology, null means ISO default
252         * @throws IllegalArgumentException if the instant is invalid
253         */
254        public YearMonthDay(Object instant, Chronology chronology) {
255            super(instant, DateTimeUtils.getChronology(chronology), ISODateTimeFormat.dateOptionalTimeParser());
256        }
257    
258        /**
259         * Constructs a YearMonthDay with specified time field values
260         * using <code>ISOChronology</code> in the default zone.
261         * <p>
262         * The constructor uses the no time zone initialising the fields as provided.
263         * Once the constructor is complete, all further calculations
264         * are performed without reference to a timezone (by switching to UTC).
265         *
266         * @param year  the year
267         * @param monthOfYear  the month of the year
268         * @param dayOfMonth  the day of the month
269         */
270        public YearMonthDay(int year, int monthOfYear, int dayOfMonth) {
271            this(year, monthOfYear, dayOfMonth, null);
272        }
273    
274        /**
275         * Constructs a YearMonthDay with specified time field values.
276         * <p>
277         * The constructor uses the time zone of the chronology specified.
278         * Once the constructor is complete, all further calculations are performed
279         * without reference to a timezone (by switching to UTC).
280         *
281         * @param year  the year
282         * @param monthOfYear  the month of the year
283         * @param dayOfMonth  the day of the month
284         * @param chronology  the chronology, null means ISOChronology in the default zone
285         */
286        public YearMonthDay(int year, int monthOfYear, int dayOfMonth, Chronology chronology) {
287            super(new int[] {year, monthOfYear, dayOfMonth}, chronology);
288        }
289    
290        /**
291         * Constructs a YearMonthDay with chronology from this instance and new values.
292         *
293         * @param partial  the partial to base this new instance on
294         * @param values  the new set of values
295         */
296        YearMonthDay(YearMonthDay partial, int[] values) {
297            super(partial, values);
298        }
299    
300        /**
301         * Constructs a YearMonthDay with values from this instance and a new chronology.
302         *
303         * @param partial  the partial to base this new instance on
304         * @param chrono  the new chronology
305         */
306        YearMonthDay(YearMonthDay partial, Chronology chrono) {
307            super(partial, chrono);
308        }
309    
310        //-----------------------------------------------------------------------
311        /**
312         * Gets the number of fields in this partial.
313         * 
314         * @return the field count
315         */
316        public int size() {
317            return 3;
318        }
319    
320        /**
321         * Gets the field for a specific index in the chronology specified.
322         * <p>
323         * This method must not use any instance variables.
324         * 
325         * @param index  the index to retrieve
326         * @param chrono  the chronology to use
327         * @return the field
328         */
329        protected DateTimeField getField(int index, Chronology chrono) {
330            switch (index) {
331                case YEAR:
332                    return chrono.year();
333                case MONTH_OF_YEAR:
334                    return chrono.monthOfYear();
335                case DAY_OF_MONTH:
336                    return chrono.dayOfMonth();
337                default:
338                    throw new IndexOutOfBoundsException("Invalid index: " + index);
339            }
340        }
341    
342        /**
343         * Gets the field type at the specified index.
344         *
345         * @param index  the index to retrieve
346         * @return the field at the specified index
347         * @throws IndexOutOfBoundsException if the index is invalid
348         */
349        public DateTimeFieldType getFieldType(int index) {
350            return FIELD_TYPES[index];
351        }
352    
353        /**
354         * Gets an array of the field type of each of the fields that this partial supports.
355         * <p>
356         * The fields are returned largest to smallest, Year, Month, Day
357         *
358         * @return the array of field types (cloned), largest to smallest
359         */
360        public DateTimeFieldType[] getFieldTypes() {
361            return (DateTimeFieldType[]) FIELD_TYPES.clone();
362        }
363    
364        //-----------------------------------------------------------------------
365        /**
366         * Returns a copy of this date with the specified chronology.
367         * This instance is immutable and unaffected by this method call.
368         * <p>
369         * This method retains the values of the fields, thus the result will
370         * typically refer to a different instant.
371         * <p>
372         * The time zone of the specified chronology is ignored, as YearMonthDay
373         * operates without a time zone.
374         *
375         * @param newChronology  the new chronology, null means ISO
376         * @return a copy of this datetime with a different chronology
377         * @throws IllegalArgumentException if the values are invalid for the new chronology
378         */
379        public YearMonthDay withChronologyRetainFields(Chronology newChronology) {
380            newChronology = DateTimeUtils.getChronology(newChronology);
381            newChronology = newChronology.withUTC();
382            if (newChronology == getChronology()) {
383                return this;
384            } else {
385                YearMonthDay newYearMonthDay = new YearMonthDay(this, newChronology);
386                newChronology.validate(newYearMonthDay, getValues());
387                return newYearMonthDay;
388            }
389        }
390    
391        /**
392         * Returns a copy of this date with the specified field set to a new value.
393         * <p>
394         * For example, if the field type is <code>dayOfMonth</code> then the day
395         * would be changed in the returned instance.
396         * <p>
397         * These three lines are equivalent:
398         * <pre>
399         * YearMonthDay updated = ymd.withField(DateTimeFieldType.dayOfMonth(), 6);
400         * YearMonthDay updated = ymd.dayOfMonth().setCopy(6);
401         * YearMonthDay updated = ymd.property(DateTimeFieldType.dayOfMonth()).setCopy(6);
402         * </pre>
403         *
404         * @param fieldType  the field type to set, not null
405         * @param value  the value to set
406         * @return a copy of this instance with the field set
407         * @throws IllegalArgumentException if the value is null or invalid
408         */
409        public YearMonthDay withField(DateTimeFieldType fieldType, int value) {
410            int index = indexOfSupported(fieldType);
411            if (value == getValue(index)) {
412                return this;
413            }
414            int[] newValues = getValues();
415            newValues = getField(index).set(this, index, newValues, value);
416            return new YearMonthDay(this, newValues);
417        }
418    
419        /**
420         * Returns a copy of this date with the value of the specified field increased.
421         * <p>
422         * If the addition is zero, then <code>this</code> is returned.
423         * <p>
424         * These three lines are equivalent:
425         * <pre>
426         * YearMonthDay added = ymd.withFieldAdded(DurationFieldType.days(), 6);
427         * YearMonthDay added = ymd.plusDays(6);
428         * YearMonthDay added = ymd.dayOfMonth().addToCopy(6);
429         * </pre>
430         * 
431         * @param fieldType  the field type to add to, not null
432         * @param amount  the amount to add
433         * @return a copy of this instance with the field updated
434         * @throws IllegalArgumentException if the value is null or invalid
435         * @throws ArithmeticException if the new datetime exceeds the capacity
436         */
437        public YearMonthDay withFieldAdded(DurationFieldType fieldType, int amount) {
438            int index = indexOfSupported(fieldType);
439            if (amount == 0) {
440                return this;
441            }
442            int[] newValues = getValues();
443            newValues = getField(index).add(this, index, newValues, amount);
444            return new YearMonthDay(this, newValues);
445        }
446    
447        /**
448         * Returns a copy of this date with the specified period added.
449         * <p>
450         * If the addition is zero, then <code>this</code> is returned.
451         * Fields in the period that aren't present in the partial are ignored.
452         * <p>
453         * This method is typically used to add multiple copies of complex
454         * period instances. Adding one field is best achieved using methods
455         * like {@link #withFieldAdded(DurationFieldType, int)}
456         * or {@link #plusYears(int)}.
457         * 
458         * @param period  the period to add to this one, null means zero
459         * @param scalar  the amount of times to add, such as -1 to subtract once
460         * @return a copy of this instance with the period added
461         * @throws ArithmeticException if the new datetime exceeds the capacity
462         */
463        public YearMonthDay withPeriodAdded(ReadablePeriod period, int scalar) {
464            if (period == null || scalar == 0) {
465                return this;
466            }
467            int[] newValues = getValues();
468            for (int i = 0; i < period.size(); i++) {
469                DurationFieldType fieldType = period.getFieldType(i);
470                int index = indexOf(fieldType);
471                if (index >= 0) {
472                    newValues = getField(index).add(this, index, newValues,
473                            FieldUtils.safeMultiply(period.getValue(i), scalar));
474                }
475            }
476            return new YearMonthDay(this, newValues);
477        }
478    
479        //-----------------------------------------------------------------------
480        /**
481         * Returns a copy of this date with the specified period added.
482         * <p>
483         * If the amount is zero or null, then <code>this</code> is returned.
484         * <p>
485         * This method is typically used to add complex period instances.
486         * Adding one field is best achieved using methods
487         * like {@link #plusYears(int)}.
488         * 
489         * @param period  the duration to add to this one, null means zero
490         * @return a copy of this instance with the period added
491         * @throws ArithmeticException if the new datetime exceeds the capacity of a long
492         */
493        public YearMonthDay plus(ReadablePeriod period) {
494            return withPeriodAdded(period, 1);
495        }
496    
497        //-----------------------------------------------------------------------
498        /**
499         * Returns a copy of this date plus the specified number of years.
500         * <p>
501         * This date instance is immutable and unaffected by this method call.
502         * <p>
503         * The following three lines are identical in effect:
504         * <pre>
505         * YearMonthDay added = dt.plusYears(6);
506         * YearMonthDay added = dt.plus(Period.years(6));
507         * YearMonthDay added = dt.withFieldAdded(DurationFieldType.years(), 6);
508         * </pre>
509         *
510         * @param years  the amount of years to add, may be negative
511         * @return the new date plus the increased years
512         * @since 1.1
513         */
514        public YearMonthDay plusYears(int years) {
515            return withFieldAdded(DurationFieldType.years(), years);
516        }
517    
518        /**
519         * Returns a copy of this date plus the specified number of months.
520         * <p>
521         * This date instance is immutable and unaffected by this method call.
522         * <p>
523         * The following three lines are identical in effect:
524         * <pre>
525         * YearMonthDay added = dt.plusMonths(6);
526         * YearMonthDay added = dt.plus(Period.months(6));
527         * YearMonthDay added = dt.withFieldAdded(DurationFieldType.months(), 6);
528         * </pre>
529         *
530         * @param months  the amount of months to add, may be negative
531         * @return the new date plus the increased months
532         * @since 1.1
533         */
534        public YearMonthDay plusMonths(int months) {
535            return withFieldAdded(DurationFieldType.months(), months);
536        }
537    
538        /**
539         * Returns a copy of this date plus the specified number of days.
540         * <p>
541         * This date instance is immutable and unaffected by this method call.
542         * <p>
543         * The following three lines are identical in effect:
544         * <pre>
545         * YearMonthDay added = dt.plusDays(6);
546         * YearMonthDay added = dt.plus(Period.days(6));
547         * YearMonthDay added = dt.withFieldAdded(DurationFieldType.days(), 6);
548         * </pre>
549         *
550         * @param days  the amount of days to add, may be negative
551         * @return the new date plus the increased days
552         * @since 1.1
553         */
554        public YearMonthDay plusDays(int days) {
555            return withFieldAdded(DurationFieldType.days(), days);
556        }
557    
558        //-----------------------------------------------------------------------
559        /**
560         * Returns a copy of this date with the specified period taken away.
561         * <p>
562         * If the amount is zero or null, then <code>this</code> is returned.
563         * <p>
564         * This method is typically used to subtract complex period instances.
565         * Subtracting one field is best achieved using methods
566         * like {@link #minusYears(int)}.
567         * 
568         * @param period  the period to reduce this instant by
569         * @return a copy of this instance with the period taken away
570         * @throws ArithmeticException if the new datetime exceeds the capacity of a long
571         */
572        public YearMonthDay minus(ReadablePeriod period) {
573            return withPeriodAdded(period, -1);
574        }
575    
576        //-----------------------------------------------------------------------
577        /**
578         * Returns a copy of this date minus the specified number of years.
579         * <p>
580         * This datetime instance is immutable and unaffected by this method call.
581         * <p>
582         * The following three lines are identical in effect:
583         * <pre>
584         * YearMonthDay subtracted = dt.minusYears(6);
585         * YearMonthDay subtracted = dt.minus(Period.years(6));
586         * YearMonthDay subtracted = dt.withFieldAdded(DurationFieldType.years(), -6);
587         * </pre>
588         *
589         * @param years  the amount of years to subtract, may be negative
590         * @return the new datetime minus the increased years
591         * @since 1.1
592         */
593        public YearMonthDay minusYears(int years) {
594            return withFieldAdded(DurationFieldType.years(), FieldUtils.safeNegate(years));
595        }
596    
597        /**
598         * Returns a copy of this date minus the specified number of months.
599         * <p>
600         * This datetime instance is immutable and unaffected by this method call.
601         * <p>
602         * The following three lines are identical in effect:
603         * <pre>
604         * YearMonthDay subtracted = dt.minusMonths(6);
605         * YearMonthDay subtracted = dt.minus(Period.months(6));
606         * YearMonthDay subtracted = dt.withFieldAdded(DurationFieldType.months(), -6);
607         * </pre>
608         *
609         * @param months  the amount of months to subtract, may be negative
610         * @return the new datetime minus the increased months
611         * @since 1.1
612         */
613        public YearMonthDay minusMonths(int months) {
614            return withFieldAdded(DurationFieldType.months(), FieldUtils.safeNegate(months));
615        }
616    
617        /**
618         * Returns a copy of this date minus the specified number of days.
619         * <p>
620         * This datetime instance is immutable and unaffected by this method call.
621         * <p>
622         * The following three lines are identical in effect:
623         * <pre>
624         * YearMonthDay subtracted = dt.minusDays(6);
625         * YearMonthDay subtracted = dt.minus(Period.days(6));
626         * YearMonthDay subtracted = dt.withFieldAdded(DurationFieldType.days(), -6);
627         * </pre>
628         *
629         * @param days  the amount of days to subtract, may be negative
630         * @return the new datetime minus the increased days
631         * @since 1.1
632         */
633        public YearMonthDay minusDays(int days) {
634            return withFieldAdded(DurationFieldType.days(), FieldUtils.safeNegate(days));
635        }
636    
637        //-----------------------------------------------------------------------
638        /**
639         * Gets the property object for the specified type, which contains
640         * many useful methods.
641         *
642         * @param type  the field type to get the property for
643         * @return the property object
644         * @throws IllegalArgumentException if the field is null or unsupported
645         */
646        public Property property(DateTimeFieldType type) {
647            return new Property(this, indexOfSupported(type));
648        }
649    
650        //-----------------------------------------------------------------------
651        /**
652         * Converts this object to a LocalDate with the same date and chronology.
653         *
654         * @return a LocalDate with the same date and chronology
655         * @since 1.3
656         */
657        public LocalDate toLocalDate() {
658            return new LocalDate(getYear(), getMonthOfYear(), getDayOfMonth(), getChronology());
659        }
660    
661        //-----------------------------------------------------------------------
662        /**
663         * Converts this YearMonthDay to a full datetime at midnight using the
664         * default time zone.
665         *
666         * @return this date as a datetime at midnight
667         */
668        public DateTime toDateTimeAtMidnight() {
669            return toDateTimeAtMidnight(null);
670        }
671    
672        /**
673         * Converts this YearMonthDay to a full datetime at midnight using the
674         * specified time zone.
675         * <p>
676         * This method uses the chronology from this instance plus the time zone
677         * specified.
678         *
679         * @param zone  the zone to use, null means default
680         * @return this date as a datetime at midnight
681         */
682        public DateTime toDateTimeAtMidnight(DateTimeZone zone) {
683            Chronology chrono = getChronology().withZone(zone);
684            return new DateTime(getYear(), getMonthOfYear(), getDayOfMonth(), 0, 0, 0, 0, chrono);
685        }
686    
687        //-----------------------------------------------------------------------
688        /**
689         * Converts this partial to a full datetime using the default time zone
690         * setting the date fields from this instance and the time fields from
691         * the current time.
692         *
693         * @return this date as a datetime with the time as the current time
694         */
695        public DateTime toDateTimeAtCurrentTime() {
696            return toDateTimeAtCurrentTime(null);
697        }
698    
699        /**
700         * Converts this partial to a full datetime using the specified time zone
701         * setting the date fields from this instance and the time fields from
702         * the current time.
703         * <p>
704         * This method uses the chronology from this instance plus the time zone
705         * specified.
706         *
707         * @param zone  the zone to use, null means default
708         * @return this date as a datetime with the time as the current time
709         */
710        public DateTime toDateTimeAtCurrentTime(DateTimeZone zone) {
711            Chronology chrono = getChronology().withZone(zone);
712            long instantMillis = DateTimeUtils.currentTimeMillis();
713            long resolved = chrono.set(this, instantMillis);
714            return new DateTime(resolved, chrono);
715        }
716    
717        //-----------------------------------------------------------------------
718        /**
719         * Converts this object to a DateMidnight in the default time zone.
720         *
721         * @return the DateMidnight instance in the default zone
722         */
723        public DateMidnight toDateMidnight() {
724            return toDateMidnight(null);
725        }
726    
727        /**
728         * Converts this object to a DateMidnight.
729         *
730         * @param zone  the zone to get the DateMidnight in, null means default
731         * @return the DateMidnight instance
732         */
733        public DateMidnight toDateMidnight(DateTimeZone zone) {
734            Chronology chrono = getChronology().withZone(zone);
735            return new DateMidnight(getYear(), getMonthOfYear(), getDayOfMonth(), chrono);
736        }
737    
738        //-----------------------------------------------------------------------
739        /**
740         * Converts this object to a DateTime using a TimeOfDay to fill in the
741         * missing fields and using the default time zone.
742         * This instance is immutable and unaffected by this method call.
743         * <p>
744         * The resulting chronology is determined by the chronology of this
745         * YearMonthDay plus the time zone.
746         * The chronology of the time is ignored - only the field values are used.
747         *
748         * @param time  the time of day to use, null means current time
749         * @return the DateTime instance
750         */
751        public DateTime toDateTime(TimeOfDay time) {
752            return toDateTime(time, null);
753        }
754    
755        /**
756         * Converts this object to a DateTime using a TimeOfDay to fill in the
757         * missing fields.
758         * This instance is immutable and unaffected by this method call.
759         * <p>
760         * The resulting chronology is determined by the chronology of this
761         * YearMonthDay plus the time zone.
762         * The chronology of the time is ignored - only the field values are used.
763         *
764         * @param time  the time of day to use, null means current time
765         * @param zone  the zone to get the DateTime in, null means default
766         * @return the DateTime instance
767         */
768        public DateTime toDateTime(TimeOfDay time, DateTimeZone zone) {
769            Chronology chrono = getChronology().withZone(zone);
770            long instant = DateTimeUtils.currentTimeMillis();
771            instant = chrono.set(this, instant);
772            if (time != null) {
773                instant = chrono.set(time, instant);
774            }
775            return new DateTime(instant, chrono);
776        }
777    
778        //-----------------------------------------------------------------------
779        /**
780         * Converts this object to an Interval representing the whole day
781         * in the default time zone.
782         *
783         * @return a interval over the day
784         */
785        public Interval toInterval() {
786            return toInterval(null);
787        }
788    
789        /**
790         * Converts this object to an Interval representing the whole day.
791         *
792         * @param zone  the zone to get the Interval in, null means default
793         * @return a interval over the day
794         */
795        public Interval toInterval(DateTimeZone zone) {
796            zone = DateTimeUtils.getZone(zone);
797            return toDateMidnight(zone).toInterval();
798        }
799    
800        //-----------------------------------------------------------------------
801        /**
802         * Get the year field value.
803         *
804         * @return the year
805         */
806        public int getYear() {
807            return getValue(YEAR);
808        }
809    
810        /**
811         * Get the month of year field value.
812         *
813         * @return the month of year
814         */
815        public int getMonthOfYear() {
816            return getValue(MONTH_OF_YEAR);
817        }
818    
819        /**
820         * Get the day of month field value.
821         *
822         * @return the day of month
823         */
824        public int getDayOfMonth() {
825            return getValue(DAY_OF_MONTH);
826        }
827    
828        //-----------------------------------------------------------------------
829        /**
830         * Returns a copy of this date with the year field updated.
831         * <p>
832         * YearMonthDay is immutable, so there are no set methods.
833         * Instead, this method returns a new instance with the value of
834         * year changed.
835         *
836         * @param year  the year to set
837         * @return a copy of this object with the field set
838         * @throws IllegalArgumentException if the value is invalid
839         * @since 1.3
840         */
841        public YearMonthDay withYear(int year) {
842            int[] newValues = getValues();
843            newValues = getChronology().year().set(this, YEAR, newValues, year);
844            return new YearMonthDay(this, newValues);
845        }
846    
847        /**
848         * Returns a copy of this date with the month of year field updated.
849         * <p>
850         * YearMonthDay is immutable, so there are no set methods.
851         * Instead, this method returns a new instance with the value of
852         * month of year changed.
853         *
854         * @param monthOfYear  the month of year to set
855         * @return a copy of this object with the field set
856         * @throws IllegalArgumentException if the value is invalid
857         * @since 1.3
858         */
859        public YearMonthDay withMonthOfYear(int monthOfYear) {
860            int[] newValues = getValues();
861            newValues = getChronology().monthOfYear().set(this, MONTH_OF_YEAR, newValues, monthOfYear);
862            return new YearMonthDay(this, newValues);
863        }
864    
865        /**
866         * Returns a copy of this date with the day of month field updated.
867         * <p>
868         * YearMonthDay is immutable, so there are no set methods.
869         * Instead, this method returns a new instance with the value of
870         * day of month changed.
871         *
872         * @param dayOfMonth  the day of month to set
873         * @return a copy of this object with the field set
874         * @throws IllegalArgumentException if the value is invalid
875         * @since 1.3
876         */
877        public YearMonthDay withDayOfMonth(int dayOfMonth) {
878            int[] newValues = getValues();
879            newValues = getChronology().dayOfMonth().set(this, DAY_OF_MONTH, newValues, dayOfMonth);
880            return new YearMonthDay(this, newValues);
881        }
882    
883        //-----------------------------------------------------------------------
884        /**
885         * Get the year field property which provides access to advanced functionality.
886         * 
887         * @return the year property
888         */
889        public Property year() {
890            return new Property(this, YEAR);
891        }
892    
893        /**
894         * Get the month of year field property which provides access to advanced functionality.
895         * 
896         * @return the month of year property
897         */
898        public Property monthOfYear() {
899            return new Property(this, MONTH_OF_YEAR);
900        }
901    
902        /**
903         * Get the day of month field property which provides access to advanced functionality.
904         * 
905         * @return the day of month property
906         */
907        public Property dayOfMonth() {
908            return new Property(this, DAY_OF_MONTH);
909        }
910    
911        //-----------------------------------------------------------------------
912        /**
913         * Output the date in the ISO8601 format YYYY-MM-DD.
914         * 
915         * @return ISO8601 formatted string
916         */
917        public String toString() {
918            return ISODateTimeFormat.yearMonthDay().print(this);
919        }
920    
921        //-----------------------------------------------------------------------
922        /**
923         * The property class for <code>YearMonthDay</code>.
924         * <p>
925         * This class binds a <code>YearMonthDay</code> to a <code>DateTimeField</code>.
926         * 
927         * @author Stephen Colebourne
928         * @since 1.0
929         * @deprecated Use LocalDate which has a much better internal implementation
930         */
931        public static class Property extends AbstractPartialFieldProperty implements Serializable {
932    
933            /** Serialization version */
934            private static final long serialVersionUID = 5727734012190224363L;
935    
936            /** The partial */
937            private final YearMonthDay iYearMonthDay;
938            /** The field index */
939            private final int iFieldIndex;
940    
941            /**
942             * Constructs a property.
943             * 
944             * @param partial  the partial instance
945             * @param fieldIndex  the index in the partial
946             */
947            Property(YearMonthDay partial, int fieldIndex) {
948                super();
949                iYearMonthDay = partial;
950                iFieldIndex = fieldIndex;
951            }
952    
953            /**
954             * Gets the field that this property uses.
955             * 
956             * @return the field
957             */
958            public DateTimeField getField() {
959                return iYearMonthDay.getField(iFieldIndex);
960            }
961    
962            /**
963             * Gets the partial that this property belongs to.
964             * 
965             * @return the partial
966             */
967            protected ReadablePartial getReadablePartial() {
968                return iYearMonthDay;
969            }
970    
971            /**
972             * Gets the partial that this property belongs to.
973             * 
974             * @return the partial
975             */
976            public YearMonthDay getYearMonthDay() {
977                return iYearMonthDay;
978            }
979    
980            /**
981             * Gets the value of this field.
982             * 
983             * @return the field value
984             */
985            public int get() {
986                return iYearMonthDay.getValue(iFieldIndex);
987            }
988    
989            //-----------------------------------------------------------------------
990            /**
991             * Adds to the value of this field in a copy of this YearMonthDay.
992             * <p>
993             * The value will be added to this field. If the value is too large to be
994             * added solely to this field then it will affect larger fields.
995             * Smaller fields are unaffected.
996             * <p>
997             * If the result would be too large, beyond the maximum year, then an
998             * IllegalArgumentException is thrown.
999             * <p>
1000             * The YearMonthDay attached to this property is unchanged by this call.
1001             * Instead, a new instance is returned.
1002             * 
1003             * @param valueToAdd  the value to add to the field in the copy
1004             * @return a copy of the YearMonthDay with the field value changed
1005             * @throws IllegalArgumentException if the value isn't valid
1006             */
1007            public YearMonthDay addToCopy(int valueToAdd) {
1008                int[] newValues = iYearMonthDay.getValues();
1009                newValues = getField().add(iYearMonthDay, iFieldIndex, newValues, valueToAdd);
1010                return new YearMonthDay(iYearMonthDay, newValues);
1011            }
1012    
1013            /**
1014             * Adds to the value of this field in a copy of this YearMonthDay wrapping
1015             * within this field if the maximum value is reached.
1016             * <p>
1017             * The value will be added to this field. If the value is too large to be
1018             * added solely to this field then it wraps within this field.
1019             * Other fields are unaffected.
1020             * <p>
1021             * For example,
1022             * <code>2004-12-20</code> addWrapField one month returns <code>2004-01-20</code>.
1023             * <p>
1024             * The YearMonthDay attached to this property is unchanged by this call.
1025             * Instead, a new instance is returned.
1026             * 
1027             * @param valueToAdd  the value to add to the field in the copy
1028             * @return a copy of the YearMonthDay with the field value changed
1029             * @throws IllegalArgumentException if the value isn't valid
1030             */
1031            public YearMonthDay addWrapFieldToCopy(int valueToAdd) {
1032                int[] newValues = iYearMonthDay.getValues();
1033                newValues = getField().addWrapField(iYearMonthDay, iFieldIndex, newValues, valueToAdd);
1034                return new YearMonthDay(iYearMonthDay, newValues);
1035            }
1036    
1037            //-----------------------------------------------------------------------
1038            /**
1039             * Sets this field in a copy of the YearMonthDay.
1040             * <p>
1041             * The YearMonthDay attached to this property is unchanged by this call.
1042             * Instead, a new instance is returned.
1043             * 
1044             * @param value  the value to set the field in the copy to
1045             * @return a copy of the YearMonthDay with the field value changed
1046             * @throws IllegalArgumentException if the value isn't valid
1047             */
1048            public YearMonthDay setCopy(int value) {
1049                int[] newValues = iYearMonthDay.getValues();
1050                newValues = getField().set(iYearMonthDay, iFieldIndex, newValues, value);
1051                return new YearMonthDay(iYearMonthDay, newValues);
1052            }
1053    
1054            /**
1055             * Sets this field in a copy of the YearMonthDay to a parsed text value.
1056             * <p>
1057             * The YearMonthDay attached to this property is unchanged by this call.
1058             * Instead, a new instance is returned.
1059             * 
1060             * @param text  the text value to set
1061             * @param locale  optional locale to use for selecting a text symbol
1062             * @return a copy of the YearMonthDay with the field value changed
1063             * @throws IllegalArgumentException if the text value isn't valid
1064             */
1065            public YearMonthDay setCopy(String text, Locale locale) {
1066                int[] newValues = iYearMonthDay.getValues();
1067                newValues = getField().set(iYearMonthDay, iFieldIndex, newValues, text, locale);
1068                return new YearMonthDay(iYearMonthDay, newValues);
1069            }
1070    
1071            /**
1072             * Sets this field in a copy of the YearMonthDay to a parsed text value.
1073             * <p>
1074             * The YearMonthDay attached to this property is unchanged by this call.
1075             * Instead, a new instance is returned.
1076             * 
1077             * @param text  the text value to set
1078             * @return a copy of the YearMonthDay with the field value changed
1079             * @throws IllegalArgumentException if the text value isn't valid
1080             */
1081            public YearMonthDay setCopy(String text) {
1082                return setCopy(text, null);
1083            }
1084    
1085            //-----------------------------------------------------------------------
1086            /**
1087             * Returns a new YearMonthDay with this field set to the maximum value
1088             * for this field.
1089             * <p>
1090             * This operation is useful for obtaining a DateTime on the last day
1091             * of the month, as month lengths vary.
1092             * <pre>
1093             * YearMonthDay lastDayOfMonth = dt.dayOfMonth().withMaximumValue();
1094             * </pre>
1095             * <p>
1096             * The YearMonthDay attached to this property is unchanged by this call.
1097             *
1098             * @return a copy of the YearMonthDay with this field set to its maximum
1099             * @since 1.2
1100             */
1101            public YearMonthDay withMaximumValue() {
1102                return setCopy(getMaximumValue());
1103            }
1104    
1105            /**
1106             * Returns a new YearMonthDay with this field set to the minimum value
1107             * for this field.
1108             * <p>
1109             * The YearMonthDay attached to this property is unchanged by this call.
1110             *
1111             * @return a copy of the YearMonthDay with this field set to its minimum
1112             * @since 1.2
1113             */
1114            public YearMonthDay withMinimumValue() {
1115                return setCopy(getMinimumValue());
1116            }
1117        }
1118    
1119    }